package com.region.spring.client;

import com.region.core.annotation.Region;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ClassPathBeanDefinitionScanner;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import org.springframework.util.StringUtils;

import java.util.Set;

/**
 * @author liujieyu
 * @date 2024/7/17 17:29
 * @desciption
 */
public class RegionClassPathBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

    private String factoryBeanReferenceName;

    private Class<? extends RegionSpringFactoryBean> beanClass = RegionSpringFactoryBean.class;

    public void setFactoryBeanReferenceName(String factoryBeanReferenceName) {
        this.factoryBeanReferenceName = factoryBeanReferenceName;
    }

    public RegionClassPathBeanDefinitionScanner(BeanDefinitionRegistry registry) {
        super(registry, false);
    }

    @Override
    protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
        addIncludeFilter(new AnnotationTypeFilter(Region.class));
        Set<BeanDefinitionHolder> beanDefinitionHolders = super.doScan(basePackages);
        if (beanDefinitionHolders != null && !beanDefinitionHolders.isEmpty()) {
            for (BeanDefinitionHolder holder : beanDefinitionHolders) {
                AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) holder.getBeanDefinition();
                beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanDefinition.getBeanClassName());

                beanDefinition.setBeanClass(this.beanClass);
                boolean explicitFactoryUsed = false;

                if (StringUtils.hasText(factoryBeanReferenceName)) {
                    beanDefinition.getPropertyValues().add("factoryBean", new RuntimeBeanReference(factoryBeanReferenceName));
                    explicitFactoryUsed = true;
                }
                if (!explicitFactoryUsed) {
                    beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
                }
            }
        }

        return beanDefinitionHolders;
    }

    @Override
    protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
        return beanDefinition.getMetadata().isInterface() && beanDefinition.getMetadata().isIndependent();
    }

}
